<!DOCTYPE html>
<html>
<head>
<title>Density of States</title>
<style>
  body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    background-color: #f0f0f0;
  }
  canvas {
    border: 1px solid #ccc;
    background-color: white;
  }
</style>
</head>
<body>
<canvas id="physicsCanvas" width="700" height="500"></canvas>
<script>
  const canvas = document.getElementById('physicsCanvas');
  const ctx = canvas.getContext('2d');

  // Style settings
  ctx.strokeStyle = 'black';
  ctx.fillStyle = 'black';
  ctx.lineWidth = 2.5;
  ctx.font = '22px sans-serif';
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';

  // --- Helper function for arrows ---
  function drawArrow(fromx, fromy, tox, toy, lineWidth = 2) {
    const headlen = 10; // length of head in pixels
    const dx = tox - fromx;
    const dy = toy - fromy;
    const angle = Math.atan2(dy, dx);
    ctx.save();
    ctx.lineWidth = lineWidth;
    ctx.beginPath();
    ctx.moveTo(fromx, fromy);
    ctx.lineTo(tox, toy);
    ctx.lineTo(tox - headlen * Math.cos(angle - Math.PI / 6), toy - headlen * Math.sin(angle - Math.PI / 6));
    ctx.moveTo(tox, toy);
    ctx.lineTo(tox - headlen * Math.cos(angle + Math.PI / 6), toy - headlen * Math.sin(angle + Math.PI / 6));
    ctx.stroke();
    ctx.restore();
  }

  // --- Main Drawing ---

  // 1. Axes
  const axisOrigin = { x: 80, y: 400 };
  const xAxisEnd = { x: 680, y: 400 };
  const yAxisStart = { x: 100, y: 400 };
  const yAxisEnd = { x: 100, y: 50 };

  drawArrow(yAxisStart.x, yAxisStart.y, yAxisEnd.x, yAxisEnd.y); // Y-axis
  drawArrow(axisOrigin.x, axisOrigin.y, xAxisEnd.x, xAxisEnd.y); // X-axis

  // Axes labels
  ctx.fillText('N(E)', yAxisEnd.x - 45, yAxisEnd.y + 10);
  ctx.fillText('E', xAxisEnd.x - 10, xAxisEnd.y + 25);

  // 2. Band Parameters
  const bandTopY = 150;
  const bandBottomY = 350;
  const bandFlatWidth = 100;
  const bandCurveTaper = 40;
  const bandHeight = bandBottomY - bandTopY;

  // --- Valence Band ---
  const vBandFlatRight = 270;
  const vBandFlatLeft = vBandFlatRight - bandFlatWidth;
  const vBandRightEdge = vBandFlatRight + bandCurveTaper;
  const vBandLeftEdge = vBandFlatLeft - bandCurveTaper;
  
  // Create path for the valence band
  const createValencePath = () => {
    ctx.beginPath();
    ctx.moveTo(vBandRightEdge, bandBottomY);
    ctx.bezierCurveTo(vBandRightEdge - 5, bandBottomY - 100, vBandFlatRight + 5, bandTopY + 20, vBandFlatRight, bandTopY);
    ctx.lineTo(vBandFlatLeft, bandTopY);
    ctx.bezierCurveTo(vBandFlatLeft - 5, bandTopY + 20, vBandLeftEdge + 5, bandBottomY - 100, vBandLeftEdge, bandBottomY);
    ctx.closePath();
  };

  createValencePath();
  
  // Hatching
  ctx.save();
  ctx.clip(); 
  ctx.lineWidth = 1.5;
  ctx.beginPath();
  // Draw diagonal lines (top-left to bottom-right)
  for(let i = vBandLeftEdge; i < vBandRightEdge + bandHeight; i += 15) {
      ctx.moveTo(i, bandTopY);
      ctx.lineTo(i - bandHeight, bandBottomY);
  }
  ctx.stroke();
  ctx.restore();
  
  // Draw the outline of the valence band on top of the hatching
  createValencePath();
  ctx.stroke();

  // --- Conduction Band ---
  const cBandFlatLeft = 430;
  const cBandFlatRight = cBandFlatLeft + bandFlatWidth;
  const cBandLeftEdge = cBandFlatLeft - bandCurveTaper;
  const cBandRightEdge = cBandFlatRight + bandCurveTaper;

  ctx.beginPath();
  ctx.moveTo(cBandRightEdge, bandBottomY);
  ctx.bezierCurveTo(cBandRightEdge - 5, bandBottomY - 100, cBandFlatRight + 5, bandTopY + 20, cBandFlatRight, bandTopY);
  ctx.lineTo(cBandFlatLeft, bandTopY);
  ctx.bezierCurveTo(cBandFlatLeft - 5, bandTopY + 20, cBandLeftEdge + 5, bandBottomY - 100, cBandLeftEdge, bandBottomY);
  ctx.closePath();
  ctx.stroke();

  // 3. Annotations
  
  // Band labels
  ctx.fillText('Valence', vBandFlatLeft + bandFlatWidth/2, 80);
  ctx.fillText('band', vBandFlatLeft + bandFlatWidth/2, 105);
  drawArrow(vBandFlatLeft + bandFlatWidth/2, 115, vBandFlatLeft + bandFlatWidth/2, bandTopY - 5);

  ctx.fillText('Conduction', cBandFlatLeft + bandFlatWidth/2, 80);
  ctx.fillText('band', cBandFlatLeft + bandFlatWidth/2, 105);
  drawArrow(cBandFlatLeft + bandFlatWidth/2, 115, cBandFlatLeft + bandFlatWidth/2, bandTopY - 5);
  
  // Energy values labels
  ctx.font = '20px sans-serif';
  
  // -6.5 eV
  ctx.beginPath();
  ctx.moveTo(vBandFlatRight, bandBottomY);
  ctx.lineTo(vBandFlatRight, bandBottomY + 10);
  ctx.stroke();
  ctx.fillText('-6.5 eV', vBandFlatRight, bandBottomY + 30);
  
  // -3 eV
  ctx.beginPath();
  ctx.moveTo(cBandFlatLeft, bandBottomY);
  ctx.lineTo(cBandFlatLeft, bandBottomY + 10);
  ctx.stroke();
  ctx.fillText('-3 eV', cBandFlatLeft, bandBottomY + 30);
  
  // 1.5 eV (Band Gap)
  const gapY = 250;
  ctx.save();
  ctx.lineWidth=2;
  ctx.beginPath();
  ctx.moveTo(vBandFlatRight, gapY);
  ctx.lineTo(cBandFlatLeft, gapY);
  // Left head
  ctx.moveTo(vBandFlatRight + 10, gapY - 6);
  ctx.lineTo(vBandFlatRight, gapY);
  ctx.lineTo(vBandFlatRight + 10, gapY + 6);
  // Right head
  ctx.moveTo(cBandFlatLeft - 10, gapY - 6);
  ctx.lineTo(cBandFlatLeft, gapY);
  ctx.lineTo(cBandFlatLeft - 10, gapY + 6);
  ctx.stroke();
  ctx.restore();
  ctx.fillStyle = 'white'; 
  const gapText = '1.5 eV';
  const gapTextWidth = ctx.measureText(gapText).width;
  const gapMidX = (vBandFlatRight + cBandFlatLeft) / 2;
  ctx.fillRect(gapMidX - gapTextWidth / 2 - 2, gapY - 12, gapTextWidth + 4, 24);
  ctx.fillStyle = 'black';
  ctx.fillText(gapText, gapMidX, gapY);
  
  // n0 label
  // Dashed line
  ctx.save();
  ctx.setLineDash([5, 5]);
  ctx.lineWidth=2;
  ctx.beginPath();
  ctx.moveTo(cBandFlatRight, bandTopY);
  ctx.lineTo(cBandFlatRight + 80, bandTopY);
  ctx.stroke();
  ctx.restore();
  drawArrow(cBandFlatRight + 75, bandTopY, cBandFlatRight + 90, bandTopY, 2);

  ctx.textAlign = 'left';
  ctx.font = '22px sans-serif';
  ctx.fillText('n\u2080 = 2 x 10\u00B2\u00B9 (cm\u00B3 eV)\u207B\u00B9', 420, 115);

  // Fig. 1.23 label
  ctx.textAlign = 'center';
  ctx.font = '22px sans-serif';
  ctx.fillText('Fig. 1.23', canvas.width / 2, 470);

</script>
</body>
</html>